from datetime import datetime, timedelta
from typing import Any, Union, Optional

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
from passlib.context import CryptContext
from sqlalchemy.orm import Session

from app.core.config import settings
from app.db.session import get_db
from app.models.user import SysUsers
from app.schemas.token import TokenPayload
from app.utils.timezone_util import now_china, utc_to_china,timestamp_to_china

# 密码加密上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# OAuth2认证
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login")

def create_access_token(subject: Union[str, Any], expires_delta: Optional[timedelta] = None) -> str:
    """
    创建JWT访问令牌
    """
    if expires_delta:
        expire = now_china() + expires_delta
    else:
        expire = now_china() + timedelta(
            minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES
        )
    to_encode = {"exp": int(expire.timestamp()), "sub": str(subject)}
    encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm="HS256")
    return encoded_jwt

def verify_password(plain_password: str, hashed_password: str) -> bool:
    """
    验证密码
    """
    return pwd_context.verify(plain_password, hashed_password)

def get_password_hash(password: str) -> str:
    """
    获取密码哈希值
    """
    return pwd_context.hash(password)

async def get_current_user(
    token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)
) -> SysUsers:
    """
    获取当前用户
    """
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无法验证凭据",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(
            token, settings.SECRET_KEY, algorithms=["HS256"]
        )
        token_data = TokenPayload(**payload)
        if timestamp_to_china(token_data.exp) < now_china():
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    
    user = db.query(SysUsers).filter(SysUsers.id == token_data.sub).first()
    if not user:
        raise credentials_exception
    return user

def get_current_active_user(
    current_user: SysUsers = Depends(get_current_user),
) -> SysUsers:
    """
    获取当前活动用户
    """
    if current_user.status == 0:  # 0表示禁用
        raise HTTPException(status_code=400, detail="用户已被禁用")
    return current_user

def is_admin(current_user: SysUsers = Depends(get_current_active_user)) -> SysUsers:
    """
    检查用户是否为管理员
    """
    if current_user.role != 1:  # 1表示管理员
        raise HTTPException(status_code=403, detail="权限不足，需要管理员权限")
    return current_user

def refresh_token(token: str = Depends(oauth2_scheme)) -> dict:
    """
    刷新token
    """
    try:
        payload = jwt.decode(
            token, settings.SECRET_KEY, algorithms=["HS256"]
        )
        token_data = TokenPayload(**payload)
        user_id = token_data.sub
        new_token = create_access_token(subject=user_id)
        return {"access_token": new_token, "token_type": "bearer"}
    except JWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无法刷新令牌，请重新登录",
            headers={"WWW-Authenticate": "Bearer"},
        )